From 4d3b19fa7cd4177d66ab6f20b52bf49ead10eb41 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 27 Aug 2009 18:04:07 +0200 Subject: [PATCH] Update shape handling For toplevels, never apply clip as shape, instead apply shape. This way we don't have to re-set it all the time as the window size changes. Furthermore, this change fixes unsetting a shape on a toplevel window which didn't actually unset the shape before. Additionally we never apply clips as shape if the shape would just be the same as the regular window size. This means we won't unnecessarily add a useless shape to most native child windows (and additionally this helps apps that do weird X stuff that don't expect these shaped windows). --- gdk/gdkinternals.h | 1 + gdk/gdkwindow.c | 90 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 74 insertions(+), 17 deletions(-) diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index 4cc45f912c..e35d9392db 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -262,6 +262,7 @@ struct _GdkWindowObject guint visibility : 2; /* The visibility wrt the toplevel (i.e. based on clip_region) */ guint native_visibility : 2; /* the native visibility of a impl windows */ guint viewable : 1; /* mapped and all parents mapped */ + guint applied_shape : 1; guint num_offscreen_children; GdkWindowPaint *implicit_paint; diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index dfacc15a20..2785702fe7 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -822,6 +822,61 @@ gdk_window_update_visibility_recursively (GdkWindowObject *private, } } +static gboolean +should_apply_clip_as_shape (GdkWindowObject *private) +{ + return + gdk_window_has_impl (private) && + /* Not for offscreens */ + private->window_type != GDK_WINDOW_OFFSCREEN && + /* or for toplevels */ + !gdk_window_is_toplevel (private) && + /* or for foreign windows */ + private->window_type != GDK_WINDOW_FOREIGN && + /* or for the root window */ + private->window_type != GDK_WINDOW_ROOT; +} + +static void +apply_shape (GdkWindowObject *private, + GdkRegion *region) +{ + GdkWindowImplIface *impl_iface; + + /* We trash whether we applied a shape so that + we can avoid unsetting it many times, which + could happen in e.g. apply_clip_as_shape as + windows get resized */ + impl_iface = GDK_WINDOW_IMPL_GET_IFACE (private->impl); + if (region) + impl_iface->shape_combine_region ((GdkWindow *)private, + region, 0, 0); + else if (private->applied_shape) + impl_iface->shape_combine_region ((GdkWindow *)private, + NULL, 0, 0); + + private->applied_shape = region != NULL; +} + +static void +apply_clip_as_shape (GdkWindowObject *private) +{ + GdkRectangle r; + + r.x = r.y = 0; + r.width = private->width; + r.height = private->height; + + /* We only apply the clip region if would differ + from the actual clip region implied by the size + of the window. This is to avoid unneccessarily + adding meaningless shapes to all native subwindows */ + if (!gdk_region_rect_equal (private->clip_region, &r)) + apply_shape (private, private->clip_region); + else + apply_shape (private, NULL); +} + static void recompute_visible_regions_internal (GdkWindowObject *private, gboolean recalculate_clip, @@ -971,21 +1026,8 @@ recompute_visible_regions_internal (GdkWindowObject *private, } if (clip_region_changed && - gdk_window_has_impl (private) && - /* Not for offscreens */ - private->window_type != GDK_WINDOW_OFFSCREEN && - /* or for non-shaped toplevels */ - (private->shaped || - (private->parent != NULL && - private->parent->window_type != GDK_WINDOW_ROOT)) && - /* or for foreign windows */ - private->window_type != GDK_WINDOW_FOREIGN && - /* or for the root window */ - private->window_type != GDK_WINDOW_ROOT - ) - { - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region ((GdkWindow *)private, private->clip_region, 0, 0); - } + should_apply_clip_as_shape (private)) + apply_clip_as_shape (private); if (recalculate_siblings && !gdk_window_is_toplevel (private)) @@ -1470,7 +1512,7 @@ gdk_window_reparent (GdkWindow *window, GdkWindowObject *new_parent_private; GdkWindowObject *old_parent; GdkScreen *screen; - gboolean show, was_mapped; + gboolean show, was_mapped, applied_clip_as_shape; gboolean do_reparent_to_impl; GdkEventMask old_native_event_mask; GdkWindowImplIface *impl_iface; @@ -1525,6 +1567,8 @@ gdk_window_reparent (GdkWindow *window, new_parent_private->window_type == GDK_WINDOW_FOREIGN) gdk_window_ensure_native (window); + applied_clip_as_shape = should_apply_clip_as_shape (private); + old_native_event_mask = 0; do_reparent_to_impl = FALSE; if (gdk_window_has_impl (private)) @@ -1616,6 +1660,13 @@ gdk_window_reparent (GdkWindow *window, if (old_parent && GDK_WINDOW_TYPE (old_parent) != GDK_WINDOW_ROOT) recompute_visible_regions (old_parent, FALSE, TRUE); + /* We used to apply the clip as the shape, but no more. + Reset this to the real shape */ + if (gdk_window_has_impl (private) && + applied_clip_as_shape && + !should_apply_clip_as_shape (private)) + apply_shape (private, private->shape); + if (do_reparent_to_impl) reparent_to_impl (private); else @@ -1714,7 +1765,8 @@ gdk_window_ensure_native (GdkWindow *window) /* The shape may not have been set, as the clip region doesn't actually change, so do it here manually */ - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region ((GdkWindow *)private, private->clip_region, 0, 0); + if (should_apply_clip_as_shape (private)) + apply_clip_as_shape (private); reparent_to_impl (private); @@ -7700,6 +7752,10 @@ gdk_window_shape_combine_region (GdkWindow *window, recompute_visible_regions (private, TRUE, FALSE); + if (gdk_window_has_impl (private) && + !should_apply_clip_as_shape (private)) + apply_shape (private, private->shape); + if (old_region) { new_region = gdk_region_copy (private->clip_region); -- 2.30.2